﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Drawing;
//using System.Linq;
using System.Web;
//using System.Web.Security;
using System.Web.UI;
//using System.Web.UI.HtmlControls;
//using System.Web.UI.WebControls;
//using System.Web.UI.WebControls.WebParts;
//using System.Xml.Linq;

using Microsoft.SqlServer.Types;
using System.Data.Sql;
using System.Data.SqlClient;

using System.Drawing.Drawing2D;


namespace DrawMap
{
    public partial class Map : System.Web.UI.Page
    {
        // Create parent class to hold our shapes
        Geometries shapes = new Geometries();

        // Default image size
        float x = 500F;
        float y = 500F;

        // parcelno to display
        string parcel = "";

        protected void Page_Load(object sender, EventArgs e)
        {
            // process inputs to allow flexible size to be returned. Catch any errors in 
            // inputs and force x and y back to defaults.
            if (null != Request["width"] && null != Request["height"])
            {
                try
                {
                    x = (float)Convert.ToDouble(Request["width"].ToString());
                    y = (float)Convert.ToDouble(Request["height"].ToString());
                }
                catch (Exception ex)
                {
                    x = 500F;
                    y = 500F;
                }
            }

            // Vet the parcelno number to ensure we're not getting injected
            if (null == Request["parcelno"])
                return;
            else 
                parcel = Request["parcelno"];

            if ((11 < parcel.Length) ||
                (parcel[3] != '-') ||
                (parcel[7] != '-'))
            {
                return;
            }



            // Get the data and build the geometry objects
            buildgeom();

            // Draw the geometries
            DrawGeometry();
        }

        // Get it
        void buildgeom()
        {
            // NOTE: Linq does not (yet) support the Geometry and Geography types
            // so we're stuck doing this the "old-fashioned" way
            SqlConnection conn = new SqlConnection("Data Source=SVR142A\\SQLSERVER2008;Initial Catalog=GIS;Persist Security Info=True;User ID=MapQuery;Password=mapquery");
            DataTable dt = new DataTable();                     
            
            // adjust this at a later date? Look into using a data source style control
            //SqlCommand cmd = new SqlCommand("select * from slo_parcel where APN like '011-%' ", conn);
            //SqlCommand cmd = new SqlCommand("select * from slo_parcel where APN like '003-578-04%' ",conn);
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = conn;
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = "getBuffer";
            cmd.Parameters.Add(new SqlParameter("@parcelno", parcel)); //"003-578-046")); //"011-011-010"));
            
            // Go get the data 
            try
            {
                conn.Open();
                SqlDataReader rd = cmd.ExecuteReader();
                dt.Load(rd);
                conn.Close();
            }
            catch (SqlException sqlx)
            {
                Response.Write("Sql Error.");
                return;
            }

            if (0 == dt.Rows.Count)
                return;


            // Process the returned data
            SqlGeometry BB = null;
            foreach (DataRow row in dt.Rows)
            {
                if (!row.IsNull("i_geom"))
                {
                    // get the geometry field into .NET variable
                    SqlGeometry g = (SqlGeometry)row["i_geom"];

                    // collect bounding box data
                    if (null == BB)
                        BB = g.STEnvelope();
                    else
                        if (g.STIsValid())
                            BB = BB.STUnion(g).STEnvelope();
                        else
                        {
                            BB = BB.STUnion(g.MakeValid()).STEnvelope();
                        }

                    // Store the point and path information 
                    GeomInfo gi = new GeomInfo(Guid.NewGuid(), g, row["APN"].ToString()); 
                    shapes.lines.Add(gi.key, gi);
                }
            }

            // save the aggregate bounding box data. This will be used to scale the drawing
            shapes.boundingbox = BB;
        }

        // Draw the shapes 
        void DrawGeometry()
        {
            if (0 == shapes.lines.Count)
                return;

            // set the scale between the "size" of the shapes returned and the requested size
            // of the final graphic
            float scale = Math.Min((float)x / shapes.boxsize.Width, (float)y / shapes.boxsize.Height);

            // create bitmap and graphics context
            //Bitmap bmp = new Bitmap((int)shapes.boxsize.Width+1, (int)shapes.boxsize.Height+1);
            Bitmap bmp = new Bitmap((int)x,(int)y);
            Graphics graph = Graphics.FromImage(bmp);

            // set the background of the image
            Brush backBrush = new SolidBrush(Color.White);
            graph.FillRectangle(backBrush, 0, 0, bmp.Size.Width, bmp.Size.Height);

            // create the transforms that will a) position the drawn shapes where we can
            // see them and b)scale them to fit in the requested bitmap size.
            Matrix m = new Matrix();
            m.Translate(-shapes.offsets.X, -shapes.offsets.Y);
            m.Scale(scale, scale, MatrixOrder.Append);
            graph.Transform = m;
            graph.SmoothingMode = SmoothingMode.AntiAlias;

            // setup for drawing the shapes
            //Color fillColor = Color.Cyan;
            Brush fillBrush; // = new SolidBrush(fillColor);

            Color penColor = Color.Black;
            Color selectedColor = Color.Red;
            int penWidth = (int)(2F / scale);
            Pen linePen = new Pen(penColor, penWidth);
            Pen selectedPen = new Pen(selectedColor, penWidth);

            // draw each complex shape
            foreach (GeomInfo shapeInfo in shapes.lines.Values)
            {
                // set the fill color for this shape
                if (parcel == shapeInfo.APN)
                    fillBrush = new HatchBrush(HatchStyle.ForwardDiagonal, selectedColor, ColorPlus.Random);
                else
                    fillBrush = new SolidBrush(ColorPlus.Random);

                // draw each simple shape contained in a complex shape
                foreach (GraphicsPath gp in shapeInfo.Path)
                {
                    if (gp.PointCount > 0)
                    {
                        if (gp.PathData.Types[gp.PathData.Types.Length - 1] == 0)
                        {
                            PointF cross = gp.PathPoints[0];

                            graph.DrawLine(linePen, cross.X, cross.Y, cross.X, cross.Y);
                            graph.DrawLine(linePen, cross.X, cross.Y, cross.X, cross.Y);
                        }
                        else
                        {
                            if (parcel == shapeInfo.APN)
                                graph.DrawPath(selectedPen, gp);
                            else
                                graph.DrawPath(linePen, gp);

                            if ((gp.PathTypes[gp.PointCount - 1] & 128) == 128)
                                graph.FillPath(fillBrush, gp);
                        }
                    }
                }
            }

            // Lastly, we need to flip the image because the shape space goes "up" from
            // the origin, while the drawing space goes "down" from the origin.
            bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);

            // save the image
            System.IO.MemoryStream ms = new System.IO.MemoryStream();
            bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
            //bmp.Save("C:/testfile.png");

            // notify the browser we're sending back something new
            //Response.ContentType = "image/png";
            Response.BinaryWrite(ms.GetBuffer());

            graph.Dispose();
            bmp.Dispose();
            ms.Dispose();
        }


    }

    /*
    /// <summary>
    /// Extra Functions for Colors
    /// </summary>
    public class ColorPlus
    {
        private static Random rand = new Random();

        // generate a color value in 0x00, 0x11, 0x22 ... 0xee, 0xff
        private static int Next()
        {
            int color = 0;

            color = rand.Next(0, 16);
            color = color * 16 + color;

            return color;
        }

        /// <summary>
        /// returns a random Color
        /// </summary>
        public static Color Random
        {
            get
            {
                return Color.FromArgb(66, Next(), Next(), Next());
            }
        }
    }
    */
}
